Home›Products›Case study
Case study · This site · 2026

Taking the apology off my homepage

My old site said hello, then apologized for itself. “site is currently in renovation,” sitting under the fold for months. I rebuilt it so the site is the work sample: a design system underneath it, and an accessibility audit I can show the numbers for.

Design systemAccessibilityInteractionFront-end
samdeo.design
Role
Everything: design, build, audit
Timeline
Ongoing, 2026
Team
Just me
Deliverables
Site, design system, style guide, legal pages
01 · My role

All of it, which is the point

Audit, design system, copy, build, accessibility pass. There was nobody to hand any of it to. Which makes this the one case study where the claim and the artifact are the same object. If I say I care about contrast ratios and structure, this page is where you go check.

I did it in the wrong order. Built the page first, then retrofitted the token set onto decisions I'd already made, then ran the accessibility audit near the end. Next time the audit goes first.

02 · The problem

A warm hello isn't a portfolio

The old site was likeable. An illustrated portrait, a soft peach gradient, “Hi! I'm Sam. Your creative visual designer.” People told me it felt friendly, and it did. It just never got to the work, and the line underneath admitted as much: apologies, site is currently in renovation.

So I set a harder brief than "look good": the site itself should be the work sample. If I claim to care about systems and accessibility, the site has to be systematic and accessible, and be able to show its receipts.

  • Show the reasoning behind the outcomes: decisions with tradeoffs attached.
  • Be built on a real design system rather than a pile of one-off styles.
  • Meet WCAG 2.1 AA, and be able to prove it with numbers.
  • Hold up on a phone and in a short browser window, as well as in a 1440 mock.
Before: warm, friendly, and permanently under renovation. An introduction with no work behind it.
After. One pinned screen, one project at a time, reasoning attached.
02 · The problem, measured

Measured, not eyeballed

I walked every text node and computed its contrast against the colour actually behind it. Compositing alpha and opacity rather than trusting the hex I'd typed. Seven pairings failed, including the primary button.

My favorite colour turned out to be unreadable. The oversized case-study numerals in pale sage sat on cream at 1.23:1. Nearly invisible, and I'd shipped them because they looked tasteful.

Element
Before
After
Fix
Case numerals (66px)
1.23:1
3.53:1
Sage 300 → 600
Primary button label
3.03:1
5.72:1
Fill → terracotta 700
Ghost buttons & tags
2.69:1
5.09:1
Base → 700 for text
Muted body text
3.57:1
5.31:1
55% → 68% ink
Small spec labels
3.58:1
6.01:1
Opacity raised
The rule that came out of it
Ramp steps 100–500 are fill-only: they never carry text on the cream ground. Text uses step 700 or ink. That single line prevents the whole class of mistake, which a one-off hex change would not have.
03 · What I decided

Extracted, in the wrong order

I designed the page first and pulled the system out of it afterwards: tokens, components, a style guide. That is backwards, and it cost me: the same padding value existed in four slightly different forms before I named it.

It did have one advantage. Every token had to justify itself against something real on screen, so the system stayed small: no speculative components nobody uses.

View the style guide →
01
Two accents, one ramp shape
Terracotta and sage each run 100–900 on the same perceptual lightness scale, so equivalent steps carry equal weight and swaps stay predictable.
02
Two surfaces, no more
Solid sand, or frosted glass. Limiting it to two stopped the page accumulating five subtly different card treatments.
03
One display voice
Caprasimo does every heading and nothing else; Figtree carries all reading. No third font earned its way in.
03 · What I decided: the rules

The rules, at a glance

Three pages of the guide do most of the governing: color, shape & surface, and type. Everything on this site, including this case study, is composed from what's below, nothing else.

Color
Cream ground, ink text, two accent ramps built in OKLCH on one lightness scale.
Shape & surface
Over-rounded containers, pills for anything pressable, and exactly two surfaces: solid sand or frosted glass.
Solid · 24px
Frosted
Pill · 999px
Type & voice
Caprasimo speaks once per section; Figtree does all the reading. Copy states the decision, then the tradeoff.
Warmth Aa
Figtree 400–700 · 15–19px body, 1.6 line height
Heading · displayBody · reading
04 · What shipped: motion

Motion with a job

Three scroll behaviours carry the site, and each answers a problem rather than decorating one.

One screen, one project
A thumbnail grid asks you to compare four things at once. Pinning a single browser frame and swapping its contents as each write-up scrolls past means you only ever consider one project, and the frame gives every screenshot the same scale.
Vertical scroll, horizontal work
Brand pieces are wide, so the visual section turns downward scrolling into leftward travel. The card nearest centre scales up and its neighbours dim, so there's always one subject. The last card lands dead-centre as the mid-point of the site.
A nav that gets out of the way
It starts full-bleed so the name reads as a header, shrinks to a centred frosted pill once you commit to scrolling, and slides away entirely when the footer arrives. Where its links would only duplicate what's already on screen.
05 · What changed

Three things I got wrong first

Scroll-driven layouts fail in ways a static mock never reveals. These are the ones worth admitting, because the fixes are the actual lesson.

I fought the browser and lost
I hand-rolled snapping so the scroll would settle on a case study. It worked for three of them and trapped you on the fourth. My code kept pulling you back while you were trying to leave. I deleted all of it and used native CSS proximity snap, which does the same job and never fights the user.
Fixed heights don't shrink
Everything held up at full height and collapsed into overlapping text in a short window, because I'd pinned a hero to 586px and a mockup to fixed pixels. Vertical rhythm is now viewport-relative, clamped padding, vh-capped media, so the layout compresses instead of colliding.
A phantom scrollbar
The page scrolled 80px sideways at every position. The cause was the blurred background blobs, bled past the edge on purpose to avoid a hard cut: they were extending the scroll width. One overflow-x on the container kept the soft edge and killed the bar.
06 · On a phone

Cut the trick, keep the content

The pinned frame is the best idea on the desktop site and the worst on a phone. At that width it crowds the writing it's meant to support. So on mobile it's removed rather than shrunk, and the case studies stack as plain reading.

The horizontal track becomes a vertical list at 4:3, the rotating background word and progress bar drop out, and the nav collapses to a hamburger over the same frosted panel. Losing the mechanism is fine. Losing the work is not.

More work

Products →